#include "videocapture.h"
#include <QDebug>

extern "C"{
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
}

const char* input_format_name = "video4linux2";

VideoCapture::VideoCapture(QObject *parent)
    : QThread{parent}
{
    // Initialize libavdevice and register all the input and output devices.
    avdevice_register_all();
}

bool VideoCapture::open(const QString &device_name)
{

    auto fmt = av_find_input_format(input_format_name);
    if(nullptr == fmt) {
        return false;
    }

    m_pCtx = avformat_alloc_context();
    AVDictionary* options = nullptr;
    av_dict_set(&options, "framerate", "60", 0);
//    av_dict_set(&options, "input_format", "mjpeg", 0);
    av_dict_set(&options, "pixel_format", "mjpeg", 0);
    int ret = avformat_open_input(&m_pCtx, device_name.toStdString().data(), fmt, &options);
    av_dict_free(&options);

    if(0 != ret){
        return false;
    }

    if(!openDecoder()){
        return false;
    }

    m_bLooping.store(true);

    this->start();

    return true;
}

void VideoCapture::close()
{
    m_bLooping.store(false);

    //    avcodec_close(m_pDecoderCtx);
    if(nullptr != m_pDecoderCtx)
        avcodec_free_context(&m_pDecoderCtx);
    if(nullptr != m_pCtx)
    {avformat_close_input(&m_pCtx);
        avformat_free_context(m_pCtx);
    }
}

void VideoCapture::run()
{
    while (m_bLooping) {
        read();
    }
}

bool VideoCapture::openDecoder()
{
    AVCodec *decoder = nullptr;
    av_find_best_stream(m_pCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
    if(nullptr == decoder) {
        return false;
    }
    m_pDecoderCtx = avcodec_alloc_context3(decoder);
    auto ret = avcodec_open2(m_pDecoderCtx, decoder, nullptr);

    return ret == 0;
}

void VideoCapture::read()
{
    AVPacket pkt;
    auto frame = av_frame_alloc();
    int ret = av_read_frame(m_pCtx, &pkt);
    avcodec_send_packet(m_pDecoderCtx, &pkt);
    avcodec_receive_frame(m_pDecoderCtx, frame);



    av_packet_unref(&pkt);
    if(AVPixelFormat::AV_PIX_FMT_YUVJ422P == frame->format){
        emit appending_frame(frame);
//        qDebug() << frame->format ;
    }

}
